package com.riddler.hadankar.prdel;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.text.DecimalFormat;


public class CalculatorActivity extends ActionBarActivity {

    // Variables
    private TextView TvDisplay;
    private double DActual = 0, Dprev = 0, ButtonMarginPerc = 0.88;
    private OperationType OperType = OperationType.NotAssigned;
    private int MaxDigits = 12, ScreenWidth = 0, ScreenHeight = 0, ContHeight = 0, RowNums = 5, CollNums = 4;
    private Boolean BIsMinus = false;

    //Properties
    private String GetDivider() {
        return GetResourceById(R.string.decimal_divider);
    }

    //System
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        try {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_prdelni_aktivita);

            // load display variable
            TvDisplay = (TextView) findViewById(R.id.display);

        } catch (Exception ex) {
            ShowError(ex, null);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.prdelni_aktivita, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    //Helpers
    private void PerformOperation(OperationType opType) {
        try {
            Dprev = Double.parseDouble(this.GetDisplayText());
            DActual = 0;
            this.SetDisplayText(0.0);
            OperType = opType;
        } catch (Exception ex) {
            ShowError(ex, null);
        }
    }

    private Double TryParseDouble(String sDouble) {
        // Prevent to display something, what is not number (Double)
        try {
            return Double.parseDouble(sDouble);
        } catch (Exception ex) {
            sDouble = "0";
            return 0.0;
        }
    }

    private void ShowError(Exception ex, String sMessage) {

        /* todo: implement logging */
        Toast.makeText(getApplicationContext(), sMessage == null ? "Something went wrong" : sMessage, Toast.LENGTH_LONG).show();
//        if (TvDisplay != null)
//            this.SetDisplayText("Error");
    }

    private String getButtonTextTxt(Button but) {
        return but.getText().toString();
    }

    private String GetDisplayText() {
        try {
            return TvDisplay.getText().toString();
        } catch (Exception ex) {
            ShowError(ex, null);
            return "";
        }
    }

    private Double GetDisplayValue() {
        try {
            return Double.parseDouble(this.GetDisplayText());
        } catch (Exception ex) {
            ShowError(ex, null);
            return 0.0;
        }
    }

    private void SetDisplayText(String sText) {
        // Prevent to display something, what is not number (Double)
        if (this.TryParseDouble(sText) == 0.0)
            sText = "0";

        // restrict to MaxDigits value
        if (sText.length() < (MaxDigits + (sText.startsWith("-") ? 1 : 0))) {
            TvDisplay.setText((BIsMinus ? "-" : "") + sText);
            BIsMinus = false;
        } else
            Toast.makeText(getApplicationContext(), GetResourceById(R.string.too_long), Toast.LENGTH_LONG).show();
    }

    private void SetDisplayText(Double dNumber) {
        // get number of digits before decimal point
        int iDigCount = Integer.toString(dNumber.intValue()).length();

        DecimalFormat df = new DecimalFormat("#.#");
        df.setMaximumFractionDigits(MaxDigits - 2 - iDigCount);
        SetDisplayText(df.format(dNumber));
    }

    private String GetResourceById(int iResId) {
        return getString(iResId);
    }

    //Events
    public void PlusClick(View view) {
        this.PerformOperation(OperationType.Plus);
    }

    public void MinusClick(View view) {
        if (GetDisplayText().equals("0"))
            BIsMinus = !BIsMinus;
        else
            this.PerformOperation(OperationType.Minus);
    }

    public void TimesClick(View view) {
        this.PerformOperation(OperationType.Times);
    }

    public void SlashClick(View view) {
        this.PerformOperation(OperationType.Div);
    }

    public void SqrtPage(View view) {
        try {
            Double iCurValue = this.GetDisplayValue();
            if (iCurValue < 0)
                ShowError(new Exception("Sqrt of negative number"), "Radix only for non-negative");
            else
                this.SetDisplayText(Math.sqrt(iCurValue));
        } catch (Exception ex) {
            ShowError(ex, null);
        }
    }

    public void Clear(View view) {
        try {
            this.SetDisplayText(0.0);
            DActual = 0;
        } catch (Exception ex) {
            ShowError(ex, null);
        }
    }

    public void ClearLast(View view) {
        try {
            String sText = this.GetDisplayText();

            if (sText.length() > 1) {
                sText = sText.substring(0, sText.length() - 1);
                this.SetDisplayText(DActual = this.TryParseDouble(sText));
            } else {
                this.SetDisplayText(0.0);
                DActual = 0;
            }
            DActual = 0;
        } catch (Exception ex) {
            ShowError(ex, null);
        }
    }

    public void EqualClick(View view) {
        switch (OperType) {
            case Plus:
                DActual = GetDisplayValue() + Dprev;
                this.SetDisplayText(DActual);
                break;
            case Minus:
                DActual = Dprev - GetDisplayValue();
                this.SetDisplayText(DActual);
                break;
            case Times:
                DActual = GetDisplayValue() * Dprev;
                this.SetDisplayText(DActual);
                break;
            case Div:
                DActual = GetDisplayValue();
                if (DActual == 0) {
                    ShowError(new Exception("Dividing by zero!"), "Dividing by zero!");
                    break;
                }
                DActual = Dprev / DActual;
                this.SetDisplayText(DActual);
                break;
        }
        OperType = OperationType.NotAssigned;
    }

    public void NumClick(View view) {
        try {
            Button but = ((Button) view);
            String sAssigned = getButtonTextTxt(but);
            String sCurrentText = TvDisplay.getText().toString();
            String sDivider = GetDivider();

            // if is not zero continue
            if (sCurrentText.equals("0") || sCurrentText.equals("-0")) {
                // check if assigned character is divider
                if (sAssigned.equals(sDivider)) {
                    SetDisplayText(sCurrentText + sAssigned);
                    DActual = 0.0;
                } else {
                    // assign number with current polarity
                    SetDisplayText((sCurrentText.equals("-0") ? "-" : "") + sAssigned);
                    DActual = Double.parseDouble(sAssigned);
                }
                // prevent add another divider
            } else if (sAssigned.equals(sDivider) && sCurrentText.contains(sDivider))
                return;
                // case of zero assignation
            else {
                SetDisplayText(sCurrentText + sAssigned);
                DActual = Double.parseDouble(sAssigned + (sAssigned.equals(GetDivider()) ? "0" : ""));
            }
        } catch (Exception ex) {
            ShowError(ex, null);
        }
    }

    // Enums
    public enum OperationType {
        Plus, Minus, Times, Div, NotAssigned, Sqrt
    }

}
